package cz.via.wowss.controller;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import cz.via.wowss.entities.Company;
import cz.via.wowss.entities.CompanyHistory;
import cz.via.wowss.entities.News;
import cz.via.wowss.entities.PlayerTransaction;
import cz.via.wowss.entities.Shareholder;
import cz.via.wowss.helper.EventGenerator;
import cz.via.wowss.helper.HistoryMaker;
import cz.via.wowss.helper.UserSessionProvider;
import cz.via.wowss.service.DatabaseService;
import cz.via.wowss.service.SecurityService;

@Controller
public class MainController {

	@Autowired
	private SecurityService securityService;

	@Autowired
	private DatabaseService databaseService;

	@Autowired
	private ApplicationContext appContext;

	private EventGenerator eg = new EventGenerator();
	private HistoryMaker hm = new HistoryMaker();

	public static EntityManagerFactory emf = Persistence
			.createEntityManagerFactory("persist-unit");

	public MainController() {
		new Thread(eg).start();
		new Thread(hm).start();
	}

	@RequestMapping(value = "/money/{playerName}", method = RequestMethod.GET, consumes = { "application/json" }, produces = { "application/json" })
	public @ResponseBody
	String money(@PathVariable("playerName") String playerName) {
		JSONArray result = new JSONArray();
		result.put(databaseService.getPlayerMoney(playerName));
		return result.toString();
	}

	@RequestMapping(value = "/buy", method = RequestMethod.POST, consumes = { "application/json" }, produces = { "application/json" })
	public @ResponseBody
	String buy(@RequestBody String json) {
		UserSessionProvider usp = appContext.getBean(UserSessionProvider.class);

		if (!usp.isAuthenticated())
			return new JSONObject().put("response", false)
					.toString();

		JSONObject buy = new JSONObject(json);
		return new JSONObject().put(
				"response",
				databaseService.buy(usp.getId(), buy.getString("what"),
						Integer.valueOf(buy.getString("count")))).toString();
	}

	@RequestMapping(value = "/sell", method = RequestMethod.POST, consumes = { "application/json" }, produces = { "application/json" })
	public @ResponseBody
	String sell(@RequestBody String json) {
		UserSessionProvider usp = appContext.getBean(UserSessionProvider.class);

		if (!usp.isAuthenticated())
			return new JSONObject().put("response", false)
					.toString();

		JSONObject sell = new JSONObject(json);
		return new JSONObject().put(
				"response",
				databaseService.sell(usp.getId(), sell.getString("what"),
						Integer.valueOf(sell.getString("count")))).toString();
	}

	/**
	 * TODO Rad bych se zde dotazoval stylem pouze "shares" A rad bych dostal
	 * seznam vsech spolecnosti, ktere maji akcie na prodej akcii ve stylu -
	 * "spolecnost - pocet k prodeji"
	 */

	// To si tu prece muzes vytahnout z toho infa co tu je a vyfiltrovat ty,
	// ktere maji stockleft == 0 a zbytek zobrazit
	// Headery pouzivat nemusis, jsou nepovinne

	@RequestMapping(value = "/companies", method = RequestMethod.GET, produces = { "application/json" })
	public @ResponseBody
	String getCompanies(
			@RequestHeader(value = "X-Order", required = false) String order,
			@RequestHeader(value = "X-Filter", required = false) String filter,
			@RequestHeader(value = "X-Base", required = false) String maxResults,
			@RequestHeader(value = "X-Offset", required = false) String offset) {
		JSONArray companies = new JSONArray();

		// TODO: vymyslet nejaky defaultni maxResults
		for (Company c : databaseService.getCompanies(order, filter,
				maxResults == null ? 100 : Integer.valueOf(maxResults),
				offset == null ? 0 : Integer.valueOf(offset))) {
			JSONObject jsonCompany = new JSONObject();
			jsonCompany.put("name", c.getName());
			jsonCompany.put("stock", c.getStock());
			jsonCompany.put("stockLeft", c.getStockLeft());
			jsonCompany.put("type", c.getType());
			jsonCompany.put("value", c.getValue());
			companies.put(jsonCompany);
		}
		return companies.toString();
	}

	/**
	 * Zde bych si nekomplikoval zivot a na nejake transakce bych se vybodnul
	 * 
	 */

	// Zatim to tu necham...neres to

	@RequestMapping(value = "/transactions", method = RequestMethod.GET, produces = { "application/json" })
	public @ResponseBody
	String getPlayerTransactions(@RequestBody String json) {
		JSONArray transactions = new JSONArray();
		JSONObject request = new JSONObject(json);
		for (PlayerTransaction t : databaseService.getPlayerTransactions(
				request.getString("player"), request.getString("from"),
				request.getString("to"))) {
			JSONObject jsonTransaction = new JSONObject();
			jsonTransaction.put("stockCount", t.getStockCount());
			jsonTransaction.put("companyName", t.getCompany().getName());
			jsonTransaction.put("date", t.getDate());
			jsonTransaction.put("pricePerStock", t.getPricePerStock());
			transactions.put(jsonTransaction);
		}
		return transactions.toString();
	}

	/**
	 * Toto bych rad predelal na dotaz "shares/info/{shareId}" A chtel bych
	 * dostat neco jako info - (Jmeno spolecnosti, cena akcie, pocet akcii
	 * celkem, typ akcie) dale graph - (nejake vzorky) // popripade rozdelit na
	 * jiny dotaz a news - (deni kolem akcie a spolecnosti)
	 */

	// Tady jsem ti rikal, at to posles tak, jak to tady je
	// specifikovane....tedz posles POST na companies s parametry - company
	// (jmeno spolecnosti), from (treba posledni tyden, takze neco jako
	// 21-11-2014 00:00), to totez jako from, ale bude tam misto toho soucasny
	// cas
	// News mas pak v samostatnem dotazu

	@RequestMapping(value = "/companies", method = RequestMethod.POST, consumes = { "application/json" }, produces = { "application/json" })
	public @ResponseBody
	String getHistory(@RequestBody String json) {
		JSONObject request = new JSONObject(json);
		JSONArray history = new JSONArray();
		JSONObject response = new JSONObject();
		Company c = databaseService.getCompany(request.getString("company"));
		for (CompanyHistory h : databaseService.getHistory(
				request.getString("company"), request.getString("from"),
				request.getString("to"))) {
			JSONObject historyJson = new JSONObject();
			historyJson.put("pricePerStock", h.getPricePerStock());
			historyJson.put("date", h.getDate());
			history.put(historyJson);
		}
		response.put("name", c.getName());
		response.put("stock", c.getStock());
		response.put("stockLeft", c.getStockLeft());
		response.put("type", c.getType());
		response.put("value", c.getValue());
		response.put("history", history);
		return response.toString();
	}

	/**
	 * TODO Rad bych se zde dotazoval stylem "shares/{playerName}" A rad bych
	 * dostal seznam vsech mych nakoupenych akcii ve stylu -
	 * "spolecnost - pocet nakoupenych"
	 */

	// TO TU PRESNE JE :)

	@RequestMapping(value = "/shares/{playerName}", method = RequestMethod.GET, produces = { "application/json" })
	public @ResponseBody
	String getShares(@PathVariable("playerName") String playerName) {
		JSONArray shares = new JSONArray();
		for (Shareholder s : databaseService.getShares(playerName)) {
			JSONObject jsonShare = new JSONObject();
			jsonShare.put("stockCount", s.getStockCount());
			jsonShare.put("company", s.getCompany().getName());
			shares.put(jsonShare);
		}
		return shares.toString();
	}

	@RequestMapping(value = "/news", method = RequestMethod.GET, produces = { "application/json" })
	public @ResponseBody
	String getNews(
			@RequestHeader(value = "X-Offset", required = false) String offset) {
		JSONArray news = new JSONArray();
		for (News n : databaseService.getNews(offset == null ? 0 : Integer
				.valueOf(offset))) {
			JSONObject jsonNews = new JSONObject();
			jsonNews.put("date", n.getDate());
			jsonNews.put("text", n.getText());
			news.put(jsonNews);
		}
		return news.toString();
	}

	@RequestMapping(value = "/news/{companyName}", method = RequestMethod.GET, produces = { "application/json" })
	public @ResponseBody
	String getNews(@PathVariable("companyName") String companyName,
			@RequestHeader(value = "X-Offset", required = false) String offset) {
		JSONArray news = new JSONArray();
		for (News n : databaseService.getNewsByType(offset == null ? 0
				: Integer.valueOf(offset), companyName)) {
			JSONObject jsonNews = new JSONObject();
			jsonNews.put("date", n.getDate());
			jsonNews.put("text", n.getText());
			news.put(jsonNews);
		}
		return news.toString();
	}

	@RequestMapping(value = "/logon", method = RequestMethod.POST, consumes = { "application/json" }, produces = { "application/json" })
	public @ResponseBody
	String logon(@RequestBody String json) {
		JSONObject request = new JSONObject(json);
		JSONObject response = new JSONObject();
		UserSessionProvider usp = appContext.getBean(UserSessionProvider.class);
		boolean success = securityService.logon(request.getString("user"),
				request.getString("pass"), usp);
		response.put("response", success);
		return response.toString();
	}

	@RequestMapping(value = "/logout", method = RequestMethod.GET, produces = { "application/json" })
	public @ResponseBody
	String logout(@RequestBody String json) {
		UserSessionProvider usp = appContext.getBean(UserSessionProvider.class);
		usp.setAuthenticated(false);
		return new JSONArray().put(true).toString();
	}
}
